Skip to content

feat(config): vaults.json schema + loader (M1a)#212

Merged
vreshch merged 1 commit into
masterfrom
feature/m1-config-schema
Jul 5, 2026
Merged

feat(config): vaults.json schema + loader (M1a)#212
vreshch merged 1 commit into
masterfrom
feature/m1-config-schema

Conversation

@vreshch

@vreshch vreshch commented Jul 5, 2026

Copy link
Copy Markdown
Member

First of two PRs for M1 - Config + registry (see the cli feature plan). Pure config layer: schema + loader. No commands, no network, no legacy migration.

What

  • vaults.schema.ts - the normative Zod schema from cli.md §1: local | git | couchdb discriminated union (hard-fail on unknown type), Discover roots, VaultsConfig with a duplicate-name refine and the ^[A-Za-z0-9_-]{1,64}$ cloud-path-segment name allowlist. $schema is written on create + accepted-and-ignored on load.
  • vaults.ts - loader: reads vaults.json then vaults.yaml (JSON wins), zero-config = empty config, atomic 0600 save that always rewrites the canonical $schema url.

Decisions

  • No legacy support. The old object-map vaults.json (memory-core 0.1.0 / Agentage Sync 0.2.3) is not migrated - a file that isn't the current array schema fails validation loudly. Users start fresh with the new schema / vault add. (Removes the cross-repo writer-coordination gate and the mcp-key call entirely.)
  • Deps: adds zod + yaml - the exact runtime deps of the sibling @agentage/memory-core. R6 package-guard amended to match; the set grows again with the daemon at M3.
  • zod-4: sync blocks use .prefault({}) (not .default({})) - zod 4 stopped re-parsing defaults, so .default({}) would leave sync: {} unfilled.

Verify

  • npm run verify green: type-check (src + e2e), eslint, prettier, 83 unit tests, build.
  • Coverage 93 / 86 / 87 / 94 (thresholds 65/70/70/70).
  • Tests cover: per-type schema defaults, unknown-type + dup-name + bad-name hard-fails, strict unknown-key rejection, ignore: [] = sync-everything, JSON+YAML load, JSON-wins, zero-config empty, atomic 0600 save round-trip + canonical $schema rewrite, and legacy-file rejection.

Follow-up (M1b, stacked next): vault list, vault add --local, vault add --git <remote>, vault remove, and the update verb (all offline). The couchdb-default vault add + POST /vaults provisioning waits on the V4 couch-channel call.

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

🎉 PR Validation ✅ PASSED

Commit: f70ce9afcf2d67b8c263bf9effcd34eff16637e1
Branch: feature/m1-config-schema

Checks:

  • ✅ Release guard (no version/changelog changes)
  • ✅ Dependencies installed
  • ✅ Type check passed
  • ✅ Linting passed
  • ✅ Format check passed
  • ✅ Tests + coverage passed
  • ✅ Build successful

Ready to merge!


🔗 View workflow run
⏰ Generated at: 2026-07-05T23:10:58.078Z

@vreshch vreshch marked this pull request as ready for review July 5, 2026 22:49
@vreshch vreshch force-pushed the feature/m1-config-schema branch from 52ced1c to a0c008a Compare July 5, 2026 22:53
@vreshch vreshch changed the title feat(config): vaults.json schema + loader + object-map migration (M1a) feat(config): vaults.json schema + loader (M1a) Jul 5, 2026
- Zod schema (vaults.schema.ts) per cli.md section 1: local|git|couchdb
  discriminated union (hard-fail on unknown type), Discover roots,
  VaultsConfig with dup-name refine + cloud-path name allowlist
- Loader (vaults.ts): JSON + YAML (JSON wins), zero-config = empty,
  atomic 0600 save with the canonical $schema url injected on write
- ensureVaultsConfig() scaffolds an empty, $schema-linked vaults.json when
  none exists (wired into setup) so a fresh machine's file has autocomplete
- No legacy migration: a non-current-schema file fails validation loudly
- Adds zod+yaml (the exact deps of sibling memory-core), pinned (no 'latest');
  R6 package guard amended
- zod-4 fix: sync blocks use .prefault({}) so inner defaults re-apply
- 85 tests green
@vreshch vreshch force-pushed the feature/m1-config-schema branch from a0c008a to f70ce9a Compare July 5, 2026 23:10
@vreshch vreshch merged commit 081f07b into master Jul 5, 2026
2 checks passed
@vreshch vreshch deleted the feature/m1-config-schema branch July 5, 2026 23:19
vreshch added a commit that referenced this pull request Jul 5, 2026
The offline command block for **M1 - Config + registry**. Second of two
PRs. **Stacked on #212** (base = `feature/m1-config-schema`) -
review/merge #212 first, then this retargets to master.

## What (all offline - no network, no auth)
- **`vault list [--json]`** - name / type / path, one line each (remote
shown for git, server for couchdb); friendly hint when empty.
- **`vault add <name>`** - `--local` (a folder that never syncs) or
`--git <remote>` (`--interval`, default 5m); `--path` (default
`~/vaults/<name>`, created if missing). Writes a valid entry, provisions
nothing.
- **`vault remove <name>`** - unregisters + drops
`~/.agentage/index/<name>.db`; markdown stays on disk.
- **`update [--check]`** - `--check` reports the verdict; otherwise `npm
i -g @agentage/cli@latest` when the registry says we're behind
(installer injected for tests). Passive check already rides `status`.
- `vault-registry.ts` holds the pure add/remove/index-path/format logic;
commands take injected `Deps`.

## Deferred (not in this PR)
- **couchdb-default `vault add`** (the account path) - `vault add` with
no flag errors with guidance. It needs `POST /vaults` provisioning + the
**V4 couch-channel** call, so it lands in the provisioning slice.
- Publishing `vaults.schema.json` on the landing (separate landing-repo
PR).

## Verify
- `npm run verify` green: type-check (src + e2e), eslint, prettier,
**109 unit tests**, build.
- **Ran the built binary end to end** (temp config dir): add
`--local`/`--git`, list + `--json`, duplicate -> exit 1, no-flag ->
"needs provisioning" exit 1, remove leaves files, `vaults.json` written
valid with `$schema` first + git sync defaults filled.
- **Offline e2e tier (@p0)** passes locally (`npx playwright test
vault-offline`, 2 passed): add -> list -> remove with no network.

## Verify (for you)
Open the diff; optionally `npm run build && node dist/cli.js vault add
demo --local --path /tmp/demo && node dist/cli.js vault list`.
vreshch added a commit that referenced this pull request Jul 5, 2026
E2E hardening for **M1** - covers every M1 acceptance criterion with
end-to-end tests. **Stacked on #213** (base =
`feature/m1b-vault-commands`); lands after #212 -> #213.

Adds `e2e/m1-requirements.test.ts` (@p0), driving the built
`dist/cli.js` against a per-test temp config dir. All offline except
`update --check` (which the verb tolerates on any network state).

## Coverage (9 tests)
| Requirement | Test |
|---|---|
| `vault add --git` writes a valid entry (interval + `$schema`) | ✓ |
| `--git` requires a remote value | ✓ |
| duplicate name rejected | ✓ |
| allowlist-failing name rejected | ✓ |
| **empty `vaults.json` still carries the `$schema` link** | ✓ |
| `remove` keeps markdown on disk, drops the index db | ✓ |
| `vaults.yaml` accepted; JSON wins when both exist | ✓ |
| malformed / unknown-type config fails loudly | ✓ |
| `update --check` reports a verdict, exits 0, never installs | ✓ |

## Verify
- `npx playwright test m1-requirements vault-offline` -> **11 passed**
locally (9 new + 2 from #213), 3.1s.
- `type-check:e2e` + `format:check` green.

Stack merge order: **#212 -> #213 -> this**. CI runs once the stack
rebases onto master.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant